package com.uiotsoft.util.mqtt;//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//



import cn.hutool.core.codec.Base64;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.uiotsoft.constant.CompressionEnum;
import com.uiotsoft.entity.*;
import com.uiotsoft.struct.JavaStruct;
import com.uiotsoft.struct.StructException;
import com.uiotsoft.util.Params;
import org.apache.log4j.Logger;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

public class MqttMessageUtil {
    private static final Logger log = Logger.getLogger(MqttMessageUtil.class);

    public MqttMessageUtil() {
    }

    public static byte[] getMessage(MqttMessagePublisher mqttMessagePublisher, Object payload, String appKey, String appSecret) throws StructException {
        String topic = mqttMessagePublisher.getTopic();
        String title = mqttMessagePublisher.getTitle();
        Boolean oldProtocol = mqttMessagePublisher.getOldProtocol();
        String version;
        if (oldProtocol) {
            version = StrUtil.isBlank(mqttMessagePublisher.getVersion()) ? "1.0" : mqttMessagePublisher.getVersion();
        } else {
            version = StrUtil.isBlank(mqttMessagePublisher.getVersion()) ? "1" : mqttMessagePublisher.getVersion();
        }

        Boolean encry = mqttMessagePublisher.getEncry();
        String compression = StrUtil.isBlank(mqttMessagePublisher.getCompression()) ? CompressionEnum.NONE.getType() : mqttMessagePublisher.getCompression();
        String userUnique = StrUtil.isBlank(mqttMessagePublisher.getUserUnique()) ? "" : mqttMessagePublisher.getUserUnique();
        String isEncry = encry ? "true" : "false";
        String msgId = StrUtil.isBlank(mqttMessagePublisher.getMsgId()) ? Convert.toStr(System.currentTimeMillis()) : mqttMessagePublisher.getMsgId();
        Params params = mqttMessagePublisher.getParams();
        if (params == null) {
            params = Params.create();
        }

        if (payload == null) {
            payload = new Object();
        }

        MqttHeader header = MqttHeader.builder().identity("server").version(version).appkey(appKey).isEncrypt(isEncry).compression(compression).clientType("cloud").userUnique(userUnique).msgId(msgId).params(params).build();
        MqttMessage mqttMessage = MqttMessage.builder().header(header).payload(payload).build();
        String messageJson = JSONObject.toJSONString(mqttMessage, new SerializerFeature[]{SerializerFeature.WriteNullStringAsEmpty});
        //log.info("E|MqttMessageUtil|getMessage|{}|{} args=[message={}]", new Object[]{topic, title, messageJson});
        return encrySign(oldProtocol, messageJson, appSecret);
    }

    public static byte[] encrySign(Boolean oldProtocol, String message, String appSecret) throws StructException {
        JSONObject jsonObject = changeMessage(message);
        if (oldProtocol) {
            return encrySignOld(jsonObject, appSecret);
        } else {
            JSONObject header = jsonObject.getJSONObject("header");
            String isZip = header.getString("compression");
            String isEncrypt = header.getString("isEncrypt");
            String appkey = header.getString("appkey");
            String version = header.getString("version");
            DataHeaderStruct dataHeader = new DataHeaderStruct();
            dataHeader.version = Convert.toByte(version);
            dataHeader.enc_flag = "true".equals(isEncrypt) ? Convert.toByte(1) : Convert.toByte(0);
            dataHeader.compress_flag = CompressionEnum.ZLIB.getType().equals(isZip) ? Convert.toByte(1) : Convert.toByte(0);
            byte[] appKeyBytes = appkey.getBytes();
            byte[] app_key = dataHeader.app_key;

            for(int i = 0; i < appKeyBytes.length; ++i) {
                app_key[i] = appKeyBytes[i];
            }

            String sign = SecureUtil.md5(message + appSecret);
            byte[] signBytes = sign.getBytes();
            byte[] signByteArray = dataHeader.sign;

            for(int i = 0; i < signBytes.length; ++i) {
                signByteArray[i] = signBytes[i];
            }

            byte[] tailBytes = "EOS".getBytes();
            byte[] tail = dataHeader.tail;

            for(int i = 0; i < tailBytes.length; ++i) {
                tail[i] = tailBytes[i];
            }

            byte[] headerBytes = "UIOT".getBytes();
            byte[] dataHeaderHeader = dataHeader.header;

            for(int i = 0; i < headerBytes.length; ++i) {
                dataHeaderHeader[i] = headerBytes[i];
            }

            byte[] dataHeaderBytes = JavaStruct.pack(dataHeader, ByteOrder.LITTLE_ENDIAN);
            byte[] encryMessage;
            if (StrUtil.isNotBlank(isEncrypt) && "true".equals(isEncrypt)) {
                AES aes = new AES(appSecret.getBytes());
                encryMessage = aes.encrypt(message);
            } else {
                encryMessage = message.getBytes();
            }

            byte[] compressMessage;
            if (StrUtil.isNotBlank(isZip) && CompressionEnum.ZLIB.getType().equals(isZip)) {
                compressMessage = compress(encryMessage);
            } else {
                compressMessage = encryMessage;
            }

            byte[] bytes = ArrayUtil.addAll(new byte[][]{dataHeaderBytes, compressMessage});
            return bytes;
        }
    }

    public static MessageWrapper getMessageData(byte[] message) {
        byte[] messageHeader = ArrayUtil.sub(message, 0, 78);
        byte[] messageBody = ArrayUtil.sub(message, 78, message.length);
        DataHeaderStruct dataHeaderStruct = new DataHeaderStruct();
        MessageWrapper dataHeader = new MessageWrapper();

        try {
            JavaStruct.unpack(dataHeaderStruct, messageHeader, ByteOrder.LITTLE_ENDIAN);
        } catch (StructException var13) {
            var13.printStackTrace();
        }

        byte[] header = dataHeaderStruct.header;
        byte[] tail = dataHeaderStruct.tail;
        byte[] headerArray = new byte[]{85, 73, 79, 84, 0};
        byte[] tailArray = new byte[]{69, 79, 83, 0};
        String appkey;
        String sign_str;
        if (Arrays.equals(headerArray, header) && Arrays.equals(tailArray, tail)) {
            byte[] app_key = dataHeaderStruct.app_key;
            appkey = new String(app_key);
            byte[] sign = dataHeaderStruct.sign;
            sign_str = new String(sign);
            dataHeader.setOldProtocol(false);
            dataHeader.setAppkey(appkey.trim());
            dataHeader.setSign(sign_str.trim());
            dataHeader.setEncry(Integer.valueOf(dataHeaderStruct.enc_flag));
            dataHeader.setVersion(Integer.valueOf(dataHeaderStruct.version));
            dataHeader.setCompress(Integer.valueOf(dataHeaderStruct.compress_flag));
            dataHeader.setMessageBody(messageBody);
            return dataHeader;
        } else {
            String messageData = new String(message);
            JSONObject messageDataObject = JSON.parseObject(messageData);
            JSONObject headerObject = messageDataObject.getJSONObject("header");
            appkey = headerObject.getString("appkey");
            dataHeader.setOldProtocol(true);
            dataHeader.setAppkey(appkey);
            dataHeader.setMessageBody(message);
            return dataHeader;
        }
    }

    public static MessageConvert decry(MessageWrapper messageWrapper, String appSecret) {
        byte[] messageBodyByte = messageWrapper.getMessageBody();
        Boolean oldProtocol = messageWrapper.getOldProtocol();
        if (oldProtocol) {
            return decryOld(messageBodyByte, appSecret);
        } else {
            MessageConvert messageConvert = new MessageConvert();
            byte[] decompressMessage;
            if (messageWrapper.getCompress() == 1) {
                decompressMessage = decompress(messageBodyByte);
            } else {
                decompressMessage = messageBodyByte;
            }

            byte[] messageByteArray;
            if (messageWrapper.getEncry() == 1) {
                AES aes = new AES(appSecret.getBytes());
                messageByteArray = aes.decrypt(decompressMessage);
            } else {
                messageByteArray = decompressMessage;
            }

            String messageBody = null;
            try {
                messageBody = new String(messageByteArray,"UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            String sign = messageWrapper.getSign();
            String signCheck = SecureUtil.md5(messageBody + appSecret);
            if (!signCheck.equals(sign)) {
                log.error("签名校验失败 message={} appSecret={}");
                messageConvert.setSignCheck(false);
                return messageConvert;
            } else {
                messageConvert.setSignCheck(true);
                messageConvert.setMessage(JSON.parseObject(messageBody));
                return messageConvert;
            }
        }
    }

    private static byte[] encrySignOld(JSONObject jsonObject, String appSecret) {
        JSONObject header = jsonObject.getJSONObject("header");
        JSONObject payload = jsonObject.getJSONObject("payload");
        String isZip = header.getString("compression");
        String isEncrypt = header.getString("isEncrypt");
        if (!StrUtil.isBlank(isEncrypt) && !"false".equals(isEncrypt)) {
            AES aes = new AES(appSecret.getBytes());
            byte[] payloadDataAes = aes.encrypt(payload.toJSONString());
            String payload16Str;
            if (StrUtil.isNotBlank(isZip) && CompressionEnum.ZLIB.getType().equals(isZip)) {
                byte[] payloadDataArrayZip = compress(payloadDataAes);
                payload16Str = HexUtil.encodeHexStr(payloadDataArrayZip);
            } else {
                payload16Str = HexUtil.encodeHexStr(payloadDataAes);
            }

            String payloadDataStr = Base64.encode(payload16Str);
            Map<String, String> paramData = new HashMap(16);
            paramData.put("data", payloadDataStr);
            String mdsStr = "header=" + header.toString() + "&payload=" + JSONObject.toJSONString(paramData, new SerializerFeature[]{SerializerFeature.WriteNullStringAsEmpty}) + appSecret;
            String sign = SecureUtil.md5(mdsStr);
            LinkedHashMap<String, Object> messageData = new LinkedHashMap();
            messageData.put("sign", sign);
            messageData.put("header", header);
            messageData.put("payload", paramData);
            String messageFinal = JSONObject.toJSONString(messageData, new SerializerFeature[]{SerializerFeature.WriteNullStringAsEmpty});
            log.debug("发送密文 message={}"+ messageFinal);
            return messageFinal.getBytes();
        } else {
            String signCheck = getSign(jsonObject, appSecret);
            jsonObject.put("sign", signCheck);
            String messageStr = jsonObject.toJSONString();
            log.debug("发送消息明文 message={}"+messageStr);
            return messageStr.getBytes();
        }
    }

    private static MessageConvert decryOld(byte[] messageBodyByte, String appSecret) {
        String message = new String(messageBodyByte);
        MessageConvert messageConvert = new MessageConvert();
        JSONObject jsonObject = changeMessage(message);
        JSONObject header = jsonObject.getJSONObject("header");
        JSONObject payload = jsonObject.getJSONObject("payload");
        String isZip = header.getString("compression");
        String sign = jsonObject.getString("sign");
        String signCheck = getSign(jsonObject, appSecret);
        if (!signCheck.equals(sign)) {
            messageConvert.setSignCheck(false);
            return messageConvert;
        } else {
            messageConvert.setSignCheck(true);
            if (!header.getBoolean("isEncrypt")) {
                messageConvert.setMessage(jsonObject);
                return messageConvert;
            } else {
                String payLoadDataBase64 = payload.getString("data");
                String payLoadDataBase64Str = Base64.decodeStr(payLoadDataBase64);
                byte[] payLoadData16Hex = HexUtil.decodeHex(payLoadDataBase64Str);
                if (StrUtil.isNotBlank(isZip) && CompressionEnum.ZLIB.getType().equals(isZip)) {
                    payLoadData16Hex = decompress(payLoadData16Hex);
                }

                AES aes = new AES(appSecret.getBytes());
                byte[] payLoadDataAesByte = aes.decrypt(payLoadData16Hex);
                String payloadDataStr = new String(payLoadDataAesByte);
                LinkedHashMap<String, Object> messageData = new LinkedHashMap();
                messageData.put("header", header);
                messageData.put("payload", JSON.parseObject(payloadDataStr, new Feature[]{Feature.OrderedField}));
                messageData.put("sign", sign);
                messageConvert.setMessage(new JSONObject(messageData));
                return messageConvert;
            }
        }
    }

    private static String getSign(JSONObject jsonObject, String appSecret) {
        JSONObject header = jsonObject.getJSONObject("header");
        JSONObject payload = jsonObject.getJSONObject("payload");
        String mdsStr = "header=" + header.toJSONString() + "&payload=" + payload.toJSONString() + appSecret;
        return SecureUtil.md5(mdsStr);
    }

    private static byte[] decompress(byte[] data) {
        Inflater decompresser = new Inflater();
        decompresser.setInput(data);
        ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);

        byte[] var4;
        try {
            byte[] buf = new byte[1024];

            int i;
            while((i = decompresser.inflate(buf)) > 0) {
                o.write(buf, 0, i);
            }

            byte[] var5 = o.toByteArray();
            return var5;
        } catch (Exception var15) {
            var4 = new byte[0];
        } finally {
            if (o != null) {
                try {
                    o.close();
                } catch (IOException var14) {
                    var14.printStackTrace();
                }
            }

            decompresser.end();
        }

        return var4;
    }

    private static byte[] compress(byte[] data) {
        Deflater compresser = new Deflater();
        compresser.setInput(data);
        compresser.finish();
        ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);

        try {
            byte[] buf = new byte[1024];

            int i;
            while((i = compresser.deflate(buf)) > 0) {
                bos.write(buf, 0, i);
            }

            byte[] var5 = bos.toByteArray();
            return var5;
        } finally {
            try {
                if (bos != null) {
                    bos.close();
                }

                compresser.end();
            } catch (IOException var12) {
                var12.printStackTrace();
            }

        }
    }

    private static JSONObject changeMessage(String message) {
        LinkedHashMap<String, Object> json = (LinkedHashMap) JSON.parseObject(message, LinkedHashMap.class, new Feature[]{Feature.OrderedField});
        JSONObject jsonObject = new JSONObject(true);
        jsonObject.putAll(json);
        return jsonObject;
    }
}
